namespace Resharper.Abstractions.CodeAnnotations
{
  using JetBrains.Annotations;
  using JetBrains.Application.Settings;
  using JetBrains.ReSharper.Psi.CSharp.Tree;
  using JetBrains.ReSharper.Psi.Tree;
  using Resharper.Abstractions.Daemons;

  /// <summary>Defines the <see cref="CodeAnnotationDaemonBase"/> class.</summary>
  public abstract class CodeAnnotationDaemonBase : DaemonBase
  {
    #region Methods

    /// <summary>
    /// Gets or sets the public assertion code.
    /// </summary>
    /// <value>The public assertion code.</value>
    [NotNull]
    public string PublicAssertionCode { get; set; }

    /// <summary>
    /// Gets or sets the non public assertion code.
    /// </summary>
    /// <value>The non public assertion code.</value>
    [NotNull]
    public string NonPublicAssertionCode { get; set; }

    /// <summary>Pres the execute.</summary>
    /// <param name="file">The file.</param>
    /// <param name="settings">The settings.</param>
    protected override void PreExecute(IFile file, IContextBoundSettingsStore settings)
    {
      base.PreExecute(file, settings);

      var psiModule = file.GetPsiModule();
      var psiServices = file.GetPsiServices();

      var attributesSet = psiServices.CacheManager.GetModuleAttributes(psiModule);
      if (attributesSet == null)
      {
        return;
      }

      foreach (var instance in attributesSet.GetAttributeInstances(true))
      {
        var attributeName = instance.GetClrName().ShortName;
        if (attributeName != "ReSharperSettingAttribute")
        {
          continue;
        }

        var nameParameter = instance.PositionParameter(0);
        if (nameParameter == null)
        {
          continue;
        }

        if (!nameParameter.IsConstant)
        {
          continue;
        }

        var name = nameParameter.ConstantValue.Value as string;
        if (name != "CodeAnnotations.PublicAssertion" && name != "CodeAnnotations.NonPublicAssertion")
        {
          continue;
        }

        var valueParameter = instance.PositionParameter(1);
        if (!valueParameter.IsConstant)
        {
          continue;
        }

        var value = valueParameter.ConstantValue.Value as string ?? string.Empty;

        if (name == "CodeAnnotations.PublicAssertion")
        {
          this.PublicAssertionCode = value;
        }
        else
        {
          this.NonPublicAssertionCode = value;
        }
      }
    }

    /// <summary>Processes the tree node.</summary>
    /// <param name="treeNode">The tree node.</param>
    protected override void ProcessTreeNode(ITreeNode treeNode)
    {
      try
      {
        if (treeNode is IMethodDeclaration)
        {
          base.ProcessTreeNode(treeNode);
          return;
        }

        if (treeNode is IPropertyDeclaration)
        {
          base.ProcessTreeNode(treeNode);
          return;
        }

        if (treeNode is IConstructorDeclaration)
        {
          base.ProcessTreeNode(treeNode);
          return;
        }

        if (treeNode is IIndexerDeclaration)
        {
          base.ProcessTreeNode(treeNode);
        }
      }
      catch
      {
        return;
      }
    }

    #endregion
  }
}